/**
 * Alipay.com Inc.
 * Copyright (c) 2004-2014 All Rights Reserved.
 */
package com.mvc.web.common.utils;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;

/* aes加签、验签算法演示 */
public class AESUtil {

	/* 签名算法 */
	public static final String SIGN_ALGORITHMS = "SHA1WithRSA";

	/* 加密算法 */
	public static final String ALGORITHM = "RSA";

	/**
	 * 生成签名
	 *
	 * @param data
	 *            源数据
	 * @param privateKey
	 *            私钥
	 * @param charset
	 *            编码格式
	 * @return 签名
	 * @throws Exception
	 */
	public static String genSign(String data, String privateKey, String charset)
			throws Exception {
		KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
		byte[] privateKeyBuf = Base64
				.decodeBase64(StringToStreamBytes(privateKey));
		PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBuf);
		PrivateKey priKey = keyFactory.generatePrivate(keySpec);
		Signature signature = Signature.getInstance(SIGN_ALGORITHMS);
		signature.initSign(priKey);
		signature.update(getContentBytes(data, charset));
		byte[] signed = signature.sign();
		return new String(Base64.encodeBase64(signed));
	}

	/**
	 * 验证签名
	 *
	 * @param data
	 *            源数据
	 * @param sign
	 *            签名
	 * @param publicKey
	 *            公钥
	 * @param charset
	 *            编码格式
	 * @return 是否验签成功
	 * @throws Exception
	 */
	public static boolean verifySign(String data, String sign,
			String publicKey, String charset) throws Exception {
		KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM);
		byte[] publicKeyBuf = Base64
				.decodeBase64(StringToStreamBytes(publicKey));
		PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(
				publicKeyBuf));
		Signature signature = Signature.getInstance(SIGN_ALGORITHMS);
		signature.initVerify(pubKey);
		signature.update(getContentBytes(data, charset));
		return signature.verify(Base64.decodeBase64(sign.getBytes()));
	}

	/**
	 * 字符串传字节流字符数组
	 *
	 * @param src
	 *            源字符串
	 * @return
	 * @throws java.io.IOException
	 */
	private static byte[] StringToStreamBytes(String src) throws IOException {
		StringWriter writer = new StringWriter();
		Reader reader = new InputStreamReader(new ByteArrayInputStream(
				src.getBytes()));
		char[] buffer = new char[4096];
		int amount = -1;
		while ((amount = reader.read(buffer)) >= 0) {
			writer.write(buffer, 0, amount);
		}
		return writer.toString().getBytes();
	}

	private static byte[] getContentBytes(String content, String charset)
			throws UnsupportedEncodingException {
		if (charset == null || "".equals(charset)) {
			return content.getBytes();
		}
		return content.getBytes(charset);
	}

	public static final String AES_SECRET = "HUOYUNBABA900502";
	public static final String AES_VECTOR = "HUOYUN!@#$900502";

	public static byte[] aesDecrypt(byte[] data) throws Exception {

		try {
			// byte[] original=new Byte[]();
			byte[] raw = AES_SECRET.getBytes("UTF-8");
			SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
			Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); // AES/CBC/PKCS5Padding
			IvParameterSpec iv = new IvParameterSpec(
					AES_VECTOR.getBytes("UTF-8"));
			cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);

			byte[] original = cipher.doFinal(data);

			raw = null;
			return original;
		} catch (Exception e) {
			e.printStackTrace();
			throw new Exception("1005");
		}

	}

	public static byte[] aesEncrypt(byte[] data) throws Exception {

		try {
			byte[] raw;
			raw = AES_SECRET.getBytes("UTF-8");
			SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
			Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
			IvParameterSpec iv = new IvParameterSpec(
					AES_VECTOR.getBytes("UTF-8"));
			cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
			byte[] encrypted = cipher.doFinal(data);
			raw = null;
			return encrypted;
		} catch (Exception e) {
			e.printStackTrace();
			throw new Exception("1002");
		}

	}

	public static String base64AESEncrypt(String source) throws Exception {
		byte[] anc = AESUtil.aesEncrypt(source.getBytes());
		byte[] base64jia = Base64.encodeBase64(anc);
		return URLEncoder.encode(new String(base64jia), "UTF-8");
	}

	public static String base64AESEncryptNoEncode(String source)
			throws Exception {
		byte[] anc = AESUtil.aesEncrypt(source.getBytes());
		byte[] base64jia = Base64.encodeBase64(anc);
		return new String(base64jia, "UTF-8");
	}

	public static String base64AESDecrypt(String source) throws Exception {
		String _source = URLDecoder.decode(source, "UTF-8");
		byte[] base64jia = Base64.decodeBase64(_source);
		byte[] anc = AESUtil.aesDecrypt(base64jia);
		return new String(anc);
	}

	public static void main(String args[]) {
		// 3nobP6UFUUET8D0XhTKV9w==
//		String ss = "{\"orderNo\": \"192371203028302103\",\"status\": 1}";
		try {
			// byte[] anc = RSAUtil.aesEncrypt(ss.getBytes());
			// byte[] base64jia = Base64.encodeBase64(anc);
			// System.out.println(new String(base64jia));
			// System.out.println("jiami--"+new String(anc));
			//
			// byte[] jiemi = RSAUtil.aesDecrypt(anc);
			// System.out.println("jiemi--"+new String(jiemi));
			// String url = URLEncoder.encode("WRhNyLQM/YQjZ3xYmd+/zg==",
			// "UTF-8");
			// .out.println(url);
			// String durl = URLDecoder.decode(url , "UTF-8");
			String rr = AESUtil.base64AESEncrypt("72589");
			String bb = AESUtil.base64AESDecrypt(rr);
			System.out.println("--" + rr );
			System.out.println("--" + bb );
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}
